home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / share / hplip / base / device.py < prev    next >
Text File  |  2008-10-13  |  85KB  |  2,365 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # (c) Copyright 2003-2008 Hewlett-Packard Development Company, L.P.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18. #
  19. # Author: Don Welch
  20. #
  21.  
  22. # Std Lib
  23. import socket
  24. import re
  25. import gzip
  26. import os.path
  27. import time
  28. import urllib # TODO: Replace with urllib2 (urllib is deprecated in Python 3.0)
  29. import StringIO
  30. import httplib
  31. import struct
  32.  
  33. # Local
  34. from g import *
  35. from codes import *
  36. import utils
  37. import status
  38. import pml
  39. from prnt import pcl, ldl, cups
  40. import models, mdns, slp
  41. from strings import StringTable
  42.  
  43.  
  44. try:
  45.     import hpmudext
  46. except ImportError:
  47.     if not os.getenv("HPLIP_BUILD"):
  48.         log.error("HPMUDEXT could not be loaded. Please check HPLIP installation.")
  49.         sys.exit(1)
  50.  
  51.  
  52. dbus_avail = False
  53. dbus_disabled = False
  54. try:
  55.     import dbus
  56.     dbus_avail = True
  57. except ImportError:
  58.     log.warn("python-dbus not installed.")
  59.  
  60.  
  61. DEFAULT_PROBE_BUS = ['usb', 'par', 'cups']
  62. VALID_BUSES = ('par', 'net', 'cups', 'usb') #, 'bt', 'fw')
  63. VALID_BUSES_WO_CUPS = ('par', 'net', 'usb')
  64. DEFAULT_FILTER = None
  65. VALID_FILTERS = ('print', 'scan', 'fax', 'pcard', 'copy')
  66.  
  67. pat_deviceuri = re.compile(r"""(.*):/(.*?)/(\S*?)\?(?:serial=(\S*)|device=(\S*)|ip=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}[^&]*))(?:&port=(\d))?""", re.IGNORECASE)
  68. http_pat_url = re.compile(r"""/(.*?)/(\S*?)\?(?:serial=(\S*)|device=(\S*))&loc=(\S*)""", re.IGNORECASE)
  69. direct_pat = re.compile(r'direct (.*?) "(.*?)" "(.*?)" "(.*?)"', re.IGNORECASE)
  70.  
  71. # Pattern to check for ; at end of CTR fields
  72. # Note: If ; not present, CTR value is invalid
  73. pat_dynamic_ctr = re.compile(r"""CTR:\d*\s.*;""", re.IGNORECASE)
  74.  
  75. MAX_BUFFER = 8192
  76.  
  77. # Cache for model data
  78. model_dat = models.ModelData()
  79.  
  80. ip_pat = re.compile(r"""\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b""", re.IGNORECASE)
  81.  
  82. dev_pat = re.compile(r"""/dev/.+""", re.IGNORECASE)
  83. usb_pat = re.compile(r"""(\d+):(\d+)""", re.IGNORECASE)
  84.  
  85.  
  86. class Event(object):
  87.     def __init__(self, device_uri, printer_name, event_code, username, job_id, title, timedate=0):
  88.         self.device_uri = str(device_uri).replace('\x00', '')
  89.         self.printer_name = str(printer_name).replace('\x00', '')
  90.         self.event_code = int(event_code)
  91.         self.username = str(username).replace('\x00', '')
  92.         self.job_id = int(job_id)
  93.         self.title = str(title).replace('\x00', '')
  94.  
  95.         if timedate:
  96.             self.timedate = float(timedate)
  97.         else:
  98.             self.timedate = time.time()
  99.  
  100.         self.fmt = "64s64sI32sI64sf"
  101.  
  102.     def debug(self):
  103.         log.debug("    device_uri=%s" % self.device_uri)
  104.         log.debug("    printer_name=%s" % self.printer_name)
  105.         log.debug("    event_code=%d" % self.event_code)
  106.         log.debug("    username=%s" % self.username)
  107.         log.debug("    job_id=%d" % self.job_id)
  108.         log.debug("    title=%s" % self.title)
  109.         log.debug("    timedate=%s" % self.timedate)
  110.  
  111.     def pack(self): # pack up for transport in pipe between hpssd and systemtray_ui and between toolbox and toolbox dbus receiver
  112.         return struct.pack(self.fmt, self.device_uri[:64], self.printer_name[:64],
  113.                 self.event_code, self.username[:32], self.job_id, self.title[:64], self.timedate)
  114.  
  115.     def __str__(self):
  116.         return "<Event('%s', '%s', %d, '%s', %d, '%s', %f)>" % self.as_tuple()
  117.  
  118.  
  119.     def as_tuple(self):
  120.         return (self.device_uri, self.printer_name, self.event_code,
  121.              self.username, self.job_id, self.title, self.timedate)
  122.  
  123.  
  124.  
  125. def init_dbus():
  126.     global dbus_avail
  127.     service = None
  128.  
  129.     if dbus_avail and not dbus_disabled:
  130.         if os.getuid() == 0:
  131.             log.debug("Not starting dbus: running as root.")
  132.             dbus_avail = False
  133.             return dbus_avail, None
  134.  
  135.         try:
  136.             session_bus = dbus.SessionBus()
  137.         except dbus.exceptions.DBusException, e:
  138.             if os.getuid() != 0:
  139.                 log.error("Unable to connect to dbus session bus.")
  140.             else:
  141.                 log.debug("Unable to connect to dbus session bus (running as root?)")
  142.  
  143.             dbus_avail = False
  144.             return dbus_avail, None
  145.  
  146.         try:
  147.             log.debug("Connecting to com.hplip.StatusService (try #1)...")
  148.             service = session_bus.get_object('com.hplip.StatusService', "/com/hplip/StatusService")
  149.             dbus_avail = True
  150.         except dbus.exceptions.DBusException, e:
  151.             try:
  152.                 os.waitpid(-1, os.WNOHANG)
  153.             except OSError:
  154.                 pass
  155.  
  156.             path = utils.which('hp-systray')
  157.             if path:
  158.                 path = os.path.join(path, 'hp-systray')
  159.             else:
  160.                 path = os.path.join(prop.home_dir, 'systray.py')
  161.                 if not os.path.exists(path):
  162.                     log.warn("Unable to start hp-systray")
  163.                     return False, None
  164.  
  165.             log.debug("Running hp-systray: %s --qt4 --force-startup" % path)
  166.             os.spawnlp(os.P_NOWAIT, path, 'hp-systray', '--qt4',
  167.                        '--force-startup')
  168.  
  169.             log.debug("Waiting for hp-systray to start...")
  170.             time.sleep(1)
  171.  
  172.             t = 2
  173.             while True:
  174.                 try:
  175.                     log.debug("Connecting to com.hplip.StatusService (try #%d)..." % t)
  176.                     service = session_bus.get_object('com.hplip.StatusService', "/com/hplip/StatusService")
  177.  
  178.                 except dbus.exceptions.DBusException, e:
  179.                     log.debug("Unable to connect to dbus. Is hp-systray running?")
  180.                     t += 1
  181.  
  182.                     if t > 5:
  183.                         return False, None
  184.  
  185.                     time.sleep(1)
  186.  
  187.                 else:
  188.                     log.debug("Connected.")
  189.                     dbus_avail = True
  190.                     break
  191.  
  192.     return dbus_avail, service
  193.  
  194.  
  195. def makeURI(param, port=1):
  196.     cups_uri, sane_uri, fax_uri = '', '', ''
  197.     found = False
  198.  
  199.     # see if the param represents a hostname
  200.     try:
  201.         param = socket.gethostbyname(param)
  202.     except socket.gaierror:
  203.         log.debug("Gethostbyname() failed. Trying other patterns...")
  204.  
  205.     if dev_pat.search(param) is not None: # parallel
  206.         log.debug("Trying parallel with %s" % param)
  207.  
  208.         result_code, uri = hpmudext.make_par_uri(param)
  209.  
  210.         if result_code == hpmudext.HPMUD_R_OK and uri:
  211.             log.debug("Found: %s" % uri)
  212.             found = True
  213.             cups_uri = uri
  214.         else:
  215.             log.debug("Not found.")
  216.  
  217.     elif usb_pat.search(param) is not None: # USB
  218.         match_obj = usb_pat.search(param)
  219.         usb_bus_id = match_obj.group(1)
  220.         usb_dev_id = match_obj.group(2)
  221.  
  222.         log.debug("Trying USB with bus=%s dev=%s..." % (usb_bus_id, usb_dev_id))
  223.         result_code, uri = hpmudext.make_usb_uri(usb_bus_id, usb_dev_id)
  224.  
  225.         if result_code == ERROR_SUCCESS and uri:
  226.             log.debug("Found: %s" % uri)
  227.             found = True
  228.             cups_uri = uri
  229.         else:
  230.             log.debug("Not found.")
  231.  
  232.     elif ip_pat.search(param) is not None: # IPv4 dotted quad
  233.         log.debug("Trying IP address %s" % param)
  234.  
  235.         result_code, uri = hpmudext.make_net_uri(param, port)
  236.  
  237.         if result_code == hpmudext.HPMUD_R_OK and uri:
  238.             log.debug("Found: %s" % uri)
  239.             found = True
  240.             cups_uri = uri
  241.         else:
  242.             log.debug("Not found.")
  243.  
  244.     else: # serial
  245.         log.debug("Trying serial number %s" % param)
  246.         devices = probeDevices(bus=['usb', 'par'])
  247.  
  248.         for d in devices:
  249.             log.debug(d)
  250.  
  251.             # usb has serial in URI...
  252.             try:
  253.                 back_end, is_hp, bus, model, serial, dev_file, host, port = \
  254.                     parseDeviceURI(d)
  255.             except Error:
  256.                 continue
  257.  
  258.             if bus == 'par': # ...parallel does not. Must get Device ID to obtain it...
  259.                 mq = queryModelByURI(d)
  260.  
  261.                 result_code, device_id = \
  262.                     hpmudext.device_open(d, mq.get('io-mode', hpmudext.HPMUD_UNI_MODE))
  263.  
  264.                 if result_code == hpmudext.HPMUD_R_OK:
  265.                     result_code, data = hpmudext.get_device_id(device_id)
  266.                     serial = parseDeviceID(data).get('SN', '')
  267.                     hpmudext.close_device(device_id)
  268.  
  269.             if serial.lower() == param.lower():
  270.                 #log.debug("Match")
  271.                 log.debug("Found: %s" % d)
  272.                 found = True
  273.                 cups_uri = d
  274.                 break
  275.             else:
  276.                 log.debug("Not found.")
  277.  
  278.     if found:
  279.         try:
  280.             mq = queryModelByURI(cups_uri)
  281.         except Error, e:
  282.             log.error("Error: %s" % e.msg)
  283.             cups_uri, sane_uri, fax_uri = '', '', ''
  284.         else:
  285.             if mq.get('scan-type', 0):
  286.                 sane_uri = cups_uri.replace("hp:", "hpaio:")
  287.  
  288.             if mq.get('fax-type', 0):
  289.                 fax_uri = cups_uri.replace("hp:", "hpfax:")
  290.  
  291.     else:
  292.         scan_uri, fax_uri = '', ''
  293.  
  294.     if cups_uri:
  295.         user_cfg.last_used.device_uri = cups_uri
  296.  
  297.     return cups_uri, sane_uri, fax_uri
  298.  
  299.  
  300. def queryModelByModel(model):
  301.     model = models.normalizeModelName(model).lower()
  302.     return model_dat[model]
  303.  
  304. def queryModelByURI(device_uri):
  305.     try:
  306.         back_end, is_hp, bus, model, \
  307.             serial, dev_file, host, port = \
  308.             parseDeviceURI(device_uri)
  309.     except Error:
  310.         raise Error(ERROR_INVALID_DEVICE_URI)
  311.     else:
  312.         return queryModelByModel(model)
  313.  
  314.  
  315. def __checkFilter(filter, mq):
  316.     for f, p in filter.items():
  317.         if f is not None:
  318.             op, val = p
  319.             if not op(mq[f], val):
  320.                 return False
  321.  
  322.     return True
  323.  
  324.  
  325. def enter_range(question, min_value, max_value, default_value=None):
  326.     while True:
  327.         user_input = raw_input(log.bold(question)).lower().strip()
  328.  
  329.         if not user_input:
  330.             if default_value is not None:
  331.                 return True, default_value
  332.  
  333.         if user_input == 'q':
  334.             return False, default_value
  335.  
  336.         try:
  337.             value_int = int(user_input)
  338.         except ValueError:
  339.             log.error('Please enter a number between %d and %d, or "q" to quit.' %
  340.                 (min_value, max_value))
  341.             continue
  342.  
  343.         if value_int < min_value or value_int > max_value:
  344.             log.error('Please enter a number between %d and %d, or "q" to quit.' %
  345.                 (min_value, max_value))
  346.             continue
  347.  
  348.         return True, value_int
  349.  
  350.  
  351.  
  352. def getInteractiveDeviceURI(bus=DEFAULT_PROBE_BUS, filter=DEFAULT_FILTER, back_end_filter=('hp',)):
  353.     probed_devices = probeDevices(bus, filter=filter)
  354.     cups_printers = cups.getPrinters()
  355.     log.debug(probed_devices)
  356.     log.debug(cups_printers)
  357.     max_deviceid_size, x, devices = 0, 0, {}
  358.  
  359.     for d in probed_devices:
  360.         printers = []
  361.  
  362.         back_end, is_hp, b, model, serial, dev_file, host, port = \
  363.             parseDeviceURI(d)
  364.  
  365.         if back_end in back_end_filter:
  366.             for p in cups_printers:
  367.                 if p.device_uri == d:
  368.                     printers.append(p.name)
  369.  
  370.             devices[x] = (d, printers)
  371.             x += 1
  372.             max_deviceid_size = max(len(d), max_deviceid_size)
  373.  
  374.     if x == 0:
  375.         log.error("No devices found.")
  376.         raise Error(ERROR_NO_PROBED_DEVICES_FOUND)
  377.  
  378.     elif x == 1:
  379.         log.info(log.bold("Using device: %s" % devices[0][0]))
  380.         user_cfg.last_used.device_uri = devices[0][0]
  381.         return devices[0][0]
  382.  
  383.     else:
  384.         last_used_device_uri = user_cfg.last_used.device_uri
  385.         last_used_index = None
  386.  
  387.         rows, cols = utils.ttysize()
  388.         if cols > 100: cols = 100
  389.  
  390.         log.info(log.bold("\nChoose device from probed devices connected on bus(es): %s:\n" % ','.join(bus)))
  391.         formatter = utils.TextFormatter(
  392.                 (
  393.                     {'width': 4},
  394.                     {'width': max_deviceid_size, 'margin': 2},
  395.                     {'width': cols-max_deviceid_size-8, 'margin': 2},
  396.                 )
  397.             )
  398.         log.info(formatter.compose(("Num.", "Device-URI", "CUPS printer(s)")))
  399.         log.info(formatter.compose(('-'*4, '-'*(max_deviceid_size), '-'*(cols-max_deviceid_size-10))))
  400.  
  401.         for y in range(x):
  402.             log.info(formatter.compose((str(y), devices[y][0], ', '.join(devices[y][1]))))
  403.  
  404.             if last_used_device_uri == devices[y][0]:
  405.                 last_used_index = y
  406.  
  407.         if last_used_index is not None:
  408.             ok, i = enter_range("\nEnter number 0...%d for device (q=quit, enter=last used device: %s) ?" %
  409.                 ((x-1), last_used_device_uri), 0, (x-1), -1)
  410.  
  411.         else:
  412.             ok, i = enter_range("\nEnter number 0...%d for device (q=quit) ?" %
  413.                 (x-1), 0, (x-1), -1)
  414.  
  415.         if not ok:
  416.             sys.exit(0)
  417.  
  418.         if last_used_index is not None and i == -1:
  419.             i = last_used_index
  420.  
  421.         user_cfg.last_used.device_uri = devices[i][0]
  422.         return devices[i][0]
  423.  
  424.  
  425. def probeDevices(bus=DEFAULT_PROBE_BUS, timeout=10,
  426.                  ttl=4, filter=DEFAULT_FILTER,  search='', net_search='slp',
  427.                  back_end_filter=('hp',)):
  428.  
  429.     num_devices, ret_devices = 0, {}
  430.  
  431.     if search:
  432.         try:
  433.             search_pat = re.compile(search, re.IGNORECASE)
  434.         except:
  435.             log.error("Invalid search pattern. Search uses standard regular expressions. For more info, see: http://www.amk.ca/python/howto/regex/")
  436.             search = ''
  437.  
  438.     for b in bus:
  439.         log.debug("Probing bus: %s" % b)
  440.         if b not in VALID_BUSES:
  441.             log.error("Invalid bus: %s" % b)
  442.             continue
  443.  
  444.         if b == 'net':
  445.             if net_search == 'slp':
  446.                 try:
  447.                     detected_devices = slp.detectNetworkDevices(ttl, timeout)
  448.                 except Error, socket.error:
  449.                     log.error("An error occured during network probe.")
  450.                     raise ERROR_INTERNAL
  451.             else:
  452.                 try:
  453.                     detected_devices = mdns.detectNetworkDevices(ttl, timeout)
  454.                 except Error, socket.error:
  455.                     log.error("An error occured during network probe.")
  456.                     raise ERROR_INTERNAL
  457.  
  458.             for ip in detected_devices:
  459.                 update_spinner()
  460.                 hn = detected_devices[ip].get('hn', '?UNKNOWN?')
  461.                 num_devices_on_jd = detected_devices[ip].get('num_devices', 0)
  462.                 num_ports_on_jd = detected_devices[ip].get('num_ports', 1)
  463.  
  464.                 if num_devices_on_jd > 0:
  465.                     for port in range(num_ports_on_jd):
  466.                         dev = detected_devices[ip].get('device%d' % (port+1), '0')
  467.  
  468.                         if dev is not None and dev != '0':
  469.                             device_id = parseDeviceID(dev)
  470.                             model = models.normalizeModelName(device_id.get('MDL', '?UNKNOWN?'))
  471.  
  472.                             if num_ports_on_jd == 1:
  473.                                 device_uri = 'hp:/net/%s?ip=%s' % (model, ip)
  474.                             else:
  475.                                 device_uri = 'hp:/net/%s?ip=%s&port=%d' % (model, ip, (port+1))
  476.  
  477.                             include = True
  478.                             mq = queryModelByModel(model)
  479.  
  480.                             if not mq:
  481.                                 log.debug("Not found.")
  482.                                 include = False
  483.  
  484.                             elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  485.                                 log.debug("Not supported.")
  486.                                 include = False
  487.  
  488.                             elif filter not in (None, 'print', 'print-type'):
  489.                                 include = __checkFilter(filter, mq)
  490.  
  491.                             if include:
  492.                                 ret_devices[device_uri] = (model, model, hn)
  493.  
  494.         elif b in ('usb', 'par'):
  495.             if b == 'par':
  496.                 bn = hpmudext.HPMUD_BUS_PARALLEL
  497.             else:
  498.                 bn = hpmudext.HPMUD_BUS_USB
  499.  
  500.             result_code, data = hpmudext.probe_devices(bn)
  501.  
  502.             if result_code == hpmudext.HPMUD_R_OK:
  503.                 for x in data.splitlines():
  504.                     m = direct_pat.match(x)
  505.  
  506.                     uri = m.group(1) or ''
  507.                     mdl = m.group(2) or ''
  508.                     desc = m.group(3) or ''
  509.                     devid = m.group(4) or ''
  510.  
  511.                     log.debug(uri)
  512.  
  513.                     try:
  514.                         back_end, is_hp, bb, model, serial, dev_file, host, port = \
  515.                             parseDeviceURI(uri)
  516.                     except Error:
  517.                         continue
  518.  
  519.                     include = True
  520.  
  521.                     if mdl and uri and is_hp:
  522.                         mq = queryModelByModel(model)
  523.  
  524.                         if not mq:
  525.                             log.debug("Not found.")
  526.                             include = False
  527.  
  528.                         elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  529.                             log.debug("Not supported.")
  530.                             include = False
  531.  
  532.                         elif filter not in (None, 'print', 'print-type'):
  533.                             include = __checkFilter(filter, mq)
  534.  
  535.                         if include:
  536.                             ret_devices[uri] = (mdl, desc, devid) # model w/ _'s, mdl w/o
  537.  
  538.         elif b == 'cups':
  539.             cups_printers = cups.getPrinters()
  540.             x = len(cups_printers)
  541.  
  542.             for p in cups_printers:
  543.                 device_uri = p.device_uri
  544.                 log.debug("%s: %s" % (device_uri, p.name))
  545.  
  546.                 if device_uri != '':
  547.                     try:
  548.                         back_end, is_hp, bs, model, serial, dev_file, host, port = \
  549.                             parseDeviceURI(device_uri)
  550.                     except Error:
  551.                         log.debug("Unrecognized URI: %s" % device_uri)
  552.                         continue
  553.  
  554.                     if not is_hp:
  555.                         continue
  556.  
  557.                     include = True
  558.                     mq = queryModelByModel(model)
  559.  
  560.                     if not mq:
  561.                         include = False
  562.                         log.debug("Not found.")
  563.  
  564.                     elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  565.                         log.debug("Not supported.")
  566.                         include = False
  567.  
  568.                     elif filter not in (None, 'print', 'print-type'):
  569.                         include = __checkFilter(filter, mq)
  570.  
  571.                     if include:
  572.                         ret_devices[device_uri] = (model, model, '')
  573.  
  574.     probed_devices = {}
  575.     for uri in ret_devices:
  576.         num_devices += 1
  577.         mdl, model, devid_or_hn = ret_devices[uri]
  578.  
  579.         include = True
  580.         if search:
  581.             match_obj = search_pat.search("%s %s %s %s" % (mdl, model, devid_or_hn, uri))
  582.  
  583.             if match_obj is None:
  584.                 log.debug("%s %s %s %s: Does not match search '%s'." % (mdl, model, devid_or_hn, uri, search))
  585.                 include = False
  586.  
  587.         if include:
  588.             probed_devices[uri] = ret_devices[uri]
  589.  
  590.     cleanup_spinner()
  591.     return probed_devices
  592.  
  593.  
  594. def getSupportedCUPSDevices(back_end_filter=['hp']):
  595.     devices = {}
  596.     printers = cups.getPrinters()
  597.  
  598.     for p in printers:
  599.         try:
  600.             back_end, is_hp, bus, model, serial, dev_file, host, port = \
  601.                 parseDeviceURI(p.device_uri)
  602.  
  603.         except Error:
  604.             continue
  605.  
  606.         if back_end_filter == '*' or back_end in back_end_filter:
  607.             try:
  608.                 devices[p.device_uri]
  609.             except KeyError:
  610.                 devices[p.device_uri] = [p.name]
  611.             else:
  612.                 devices[p.device_uri].append(p.name)
  613.  
  614.     return devices # { 'device_uri' : [ CUPS printer list ], ... }
  615.  
  616.  
  617. def parseDeviceID(device_id):
  618.     d= {}
  619.     x = [y.strip() for y in device_id.strip().split(';') if y]
  620.  
  621.     for z in x:
  622.         y = z.split(':')
  623.         try:
  624.             d.setdefault(y[0].strip(), y[1])
  625.         except IndexError:
  626.             d.setdefault(y[0].strip(), None)
  627.  
  628.     d.setdefault('MDL', '')
  629.     d.setdefault('SN',  '')
  630.  
  631.     if 'MODEL' in d:
  632.         d['MDL'] = d['MODEL']
  633.         del d['MODEL']
  634.  
  635.     if 'SERIAL' in d:
  636.         d['SN'] = d['SERIAL']
  637.         del d['SERIAL']
  638.  
  639.     elif 'SERN' in d:
  640.         d['SN'] = d['SERN']
  641.         del d['SERN']
  642.  
  643.     if d['SN'].startswith('X'):
  644.         d['SN'] = ''
  645.  
  646.     return d
  647.  
  648.  
  649. def parseDynamicCounter(ctr_field, convert_to_int=True):
  650.     counter, value = ctr_field.split(' ')
  651.     try:
  652.         counter = int(utils.xlstrip(str(counter), '0') or '0')
  653.  
  654.         if convert_to_int:
  655.             value = int(utils.xlstrip(str(value), '0') or '0')
  656.     except ValueError:
  657.         if convert_to_int:
  658.             counter, value = 0, 0
  659.         else:
  660.             counter, value = 0, ''
  661.  
  662.     return counter, value
  663.  
  664.  
  665. def parseDeviceURI(device_uri):
  666.     #print repr(pat_deviceuri)
  667.     #print repr(device_uri)
  668.     m = pat_deviceuri.match(device_uri)
  669.  
  670.     if m is None:
  671.         log.debug("Device URI %s is invalid/unknown" % device_uri)
  672.         raise Error(ERROR_INVALID_DEVICE_URI)
  673.  
  674.     back_end = m.group(1).lower() or ''
  675.     is_hp = (back_end in ('hp', 'hpfax', 'hpaio'))
  676.     bus = m.group(2).lower() or ''
  677.  
  678.     if bus not in ('usb', 'net', 'bt', 'fw', 'par'):
  679.         log.debug("Device URI %s is invalid/unknown" % device_uri)
  680.         raise Error(ERROR_INVALID_DEVICE_URI)
  681.  
  682.     model = m.group(3) or ''
  683.     serial = m.group(4) or ''
  684.     dev_file = m.group(5) or ''
  685.     host = m.group(6) or ''
  686.     port = m.group(7) or 1
  687.  
  688.     if bus == 'net':
  689.         try:
  690.             port = int(port)
  691.         except (ValueError, TypeError):
  692.             port = 1
  693.  
  694.         if port == 0:
  695.             port = 1
  696.  
  697.     return back_end, is_hp, bus, model, serial, dev_file, host, port
  698.  
  699.  
  700. def validateBusList(bus, allow_cups=True):
  701.     for b in bus:
  702.         if allow_cups:
  703.             vb = VALID_BUSES
  704.         else:
  705.             vb = VALID_BUSES_WO_CUPS
  706.  
  707.         if b not in vb:
  708.             log.error("Invalid bus name: %s" %b)
  709.             return False
  710.  
  711.     return True
  712.  
  713.  
  714. def validateFilterList(filter):
  715.     if filter is None:
  716.         return True
  717.  
  718.     for f in filter:
  719.         if f not in VALID_FILTERS:
  720.             log.error("Invalid term '%s' in filter list" % f)
  721.             return False
  722.  
  723.     return True
  724.  
  725.  
  726. inter_pat = re.compile(r"""%(.*)%""", re.IGNORECASE)
  727. st = StringTable()
  728. strings_init = False
  729.  
  730.  
  731. def initStrings():
  732.     global strings_init, st
  733.     strings_init = True
  734.     cycles = 0
  735.  
  736.     while True:
  737.         found = False
  738.  
  739.         for s in st.string_table:
  740.             short_string, long_string = st.string_table[s]
  741.             short_replace, long_replace = short_string, long_string
  742.  
  743.             try:
  744.                 short_match = inter_pat.match(short_string).group(1)
  745.             except (AttributeError, TypeError):
  746.                 short_match = None
  747.  
  748.             if short_match is not None:
  749.                 found = True
  750.  
  751.                 try:
  752.                     short_replace, dummy = st.string_table[short_match]
  753.                 except KeyError:
  754.                     log.error("String interpolation error: %s" % short_match)
  755.  
  756.             try:
  757.                 long_match = inter_pat.match(long_string).group(1)
  758.             except (AttributeError, TypeError):
  759.                 long_match = None
  760.  
  761.             if long_match is not None:
  762.                 found = True
  763.  
  764.                 try:
  765.                     dummy, long_replace = st.string_table[long_match]
  766.                 except KeyError:
  767.                     log.error("String interpolation error: %s" % long_match)
  768.  
  769.             if found:
  770.                 st.string_table[s] = (short_replace, long_replace)
  771.  
  772.         if not found:
  773.             break
  774.         else:
  775.             cycles +=1
  776.             if cycles > 1000:
  777.                 break
  778.  
  779.  
  780. def queryString(string_id, typ=0):
  781.     if not strings_init:
  782.         initStrings()
  783.  
  784.     #log.debug("queryString(%s)" % string_id)
  785.     s = st.string_table.get(str(string_id), ('', ''))[typ]
  786.  
  787.     if type(s) == type(''):
  788.         return s
  789.  
  790.     return s()
  791.  
  792.  
  793. AGENT_types = { AGENT_TYPE_NONE        : 'invalid',
  794.                 AGENT_TYPE_BLACK       : 'black',
  795.                 AGENT_TYPE_CMY         : 'cmy',
  796.                 AGENT_TYPE_KCM         : 'kcm',
  797.                 AGENT_TYPE_CYAN        : 'cyan',
  798.                 AGENT_TYPE_MAGENTA     : 'magenta',
  799.                 AGENT_TYPE_YELLOW      : 'yellow',
  800.                 AGENT_TYPE_CYAN_LOW    : 'photo_cyan',
  801.                 AGENT_TYPE_MAGENTA_LOW : 'photo_magenta',
  802.                 AGENT_TYPE_YELLOW_LOW  : 'photo_yellow',
  803.                 AGENT_TYPE_GGK         : 'photo_gray',
  804.                 AGENT_TYPE_BLUE        : 'photo_blue',
  805.                 AGENT_TYPE_KCMY_CM     : 'kcmy_cm',
  806.                 AGENT_TYPE_LC_LM       : 'photo_cyan_and_photo_magenta',
  807.                 #AGENT_TYPE_Y_M         : 'yellow_and_magenta',
  808.                 #AGENT_TYPE_C_K         : 'cyan_and_black',
  809.                 AGENT_TYPE_LG_PK       : 'light_gray_and_photo_black',
  810.                 AGENT_TYPE_LG          : 'light_gray',
  811.                 AGENT_TYPE_G           : 'medium_gray',
  812.                 AGENT_TYPE_PG          : 'photo_gray',
  813.                 AGENT_TYPE_C_M         : 'cyan_and_magenta',
  814.                 AGENT_TYPE_K_Y         : 'black_and_yellow',
  815.                 AGENT_TYPE_UNSPECIFIED : 'unspecified', # Kind=5,6
  816.             }
  817.  
  818. AGENT_kinds = {AGENT_KIND_NONE            : 'invalid',
  819.                 AGENT_KIND_HEAD            : 'head',
  820.                 AGENT_KIND_SUPPLY          : 'supply',
  821.                 AGENT_KIND_HEAD_AND_SUPPLY : 'cartridge',
  822.                 AGENT_KIND_TONER_CARTRIDGE : 'toner',
  823.                 AGENT_KIND_MAINT_KIT       : 'maint_kit', # fuser
  824.                 AGENT_KIND_ADF_KIT         : 'adf_kit',
  825.                 AGENT_KIND_DRUM_KIT        : 'drum_kit',
  826.                 AGENT_KIND_TRANSFER_KIT    : 'transfer_kit',
  827.                 AGENT_KIND_INT_BATTERY     : 'battery',
  828.                 AGENT_KIND_UNKNOWN         : 'unknown',
  829.               }
  830.  
  831. AGENT_healths = {AGENT_HEALTH_OK           : 'ok',
  832.                   AGENT_HEALTH_MISINSTALLED : 'misinstalled', # supply/cart
  833.                   #AGENT_HEALTH_FAIR_MODERATE : '',
  834.                   AGENT_HEALTH_INCORRECT    : 'incorrect',
  835.                   AGENT_HEALTH_FAILED       : 'failed',
  836.                   AGENT_HEALTH_OVERTEMP     : 'overtemp', # battery
  837.                   AGENT_HEALTH_CHARGING     : 'charging', # battery
  838.                   AGENT_HEALTH_DISCHARGING  : 'discharging', # battery
  839.                 }
  840.  
  841.  
  842. AGENT_levels = {AGENT_LEVEL_TRIGGER_MAY_BE_LOW : 'low',
  843.                  AGENT_LEVEL_TRIGGER_PROBABLY_OUT : 'low',
  844.                  AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT : 'out',
  845.                }
  846.  
  847.  
  848. ##MODEL_UI_REPLACEMENTS = {'laserjet'   : 'LaserJet',
  849. ##                          'psc'        : 'PSC',
  850. ##                          'officejet'  : 'Officejet',
  851. ##                          'deskjet'    : 'Deskjet',
  852. ##                          'hp'         : 'HP',
  853. ##                          'business'   : 'Business',
  854. ##                          'inkjet'     : 'Inkjet',
  855. ##                          'photosmart' : 'Photosmart',
  856. ##                          'color'      : 'Color',
  857. ##                          'series'     : 'series',
  858. ##                          'printer'    : 'Printer',
  859. ##                          'mfp'        : 'MFP',
  860. ##                          'mopier'     : 'Mopier',
  861. ##                          'pro'        : 'Pro',
  862. ##                        }
  863.  
  864.  
  865. ##def normalizeModelUIName(model):
  866. ##    if not model.lower().startswith('hp'):
  867. ##        z = 'HP ' + model.replace('_', ' ')
  868. ##    else:
  869. ##        z = model.replace('_', ' ')
  870. ##
  871. ##    y = []
  872. ##    for x in z.split():
  873. ##        xx = x.lower()
  874. ##        y.append(models.MODEL_UI_REPLACEMENTS.get(xx, xx))
  875. ##
  876. ##    return ' '.join(y)
  877.  
  878. ##def normalizeModelName(model):
  879. ##    return utils.xstrip(model.replace(' ', '_').replace('__', '_').replace('~','').replace('/', '_'), '_')
  880.  
  881.  
  882. def isLocal(bus):
  883.     return bus in ('par', 'usb', 'fw', 'bt')
  884.  
  885.  
  886. # **************************************************************************** #
  887.  
  888. string_cache = {}
  889.  
  890. class Device(object):
  891.     def __init__(self, device_uri, printer_name=None,
  892.                  service=None, callback=None, disable_dbus=False):
  893.  
  894.         log.debug("Device URI: %s" % device_uri)
  895.         log.debug("Printer: %s" % printer_name)
  896.  
  897.         global dbus_disabled
  898.         dbus_disabled = disable_dbus
  899.         
  900.         if not disable_dbus:
  901.             if service is None:
  902.                 self.dbus_avail, self.service = init_dbus()
  903.             else:
  904.                 self.dbus_avail = True
  905.                 self.service = service
  906.         else:
  907.             self.dbus_avail = False
  908.             self.service = None
  909.  
  910.         self.last_event = None # Used in devmgr if dbus is disabled
  911.  
  912.         printers = cups.getPrinters()
  913.  
  914.         if device_uri is None and printer_name is not None:
  915.             for p in printers:
  916.                 if p.name.lower() == printer_name.lower():
  917.                     device_uri = p.device_uri
  918.                     break
  919.             else:
  920.                 raise Error(ERROR_DEVICE_NOT_FOUND)
  921.  
  922.         self.device_uri = device_uri
  923.         self.callback = callback
  924.         self.device_type = DEVICE_TYPE_UNKNOWN
  925.         
  926.         if self.device_uri.startswith('hp:'):
  927.             self.device_type = DEVICE_TYPE_PRINTER
  928.         
  929.         elif self.device_uri.startswith('hpaio:'):
  930.             self.device_type = DEVICE_TYPE_SCANNER
  931.         
  932.         elif self.device_uri.startswith('hpfax:'):
  933.             self.device_type = DEVICE_TYPE_FAX
  934.         
  935.         try:
  936.             self.back_end, self.is_hp, self.bus, self.model, \
  937.                 self.serial, self.dev_file, self.host, self.port = \
  938.                 parseDeviceURI(self.device_uri)
  939.         except Error:
  940.             self.io_state = IO_STATE_NON_HP
  941.             raise Error(ERROR_INVALID_DEVICE_URI)
  942.  
  943.         log.debug("URI: backend=%s, is_hp=%s, bus=%s, model=%s, serial=%s, dev=%s, host=%s, port=%d" % \
  944.             (self.back_end, self.is_hp, self.bus, self.model, self.serial, self.dev_file, self.host, self.port))
  945.  
  946.         self.model_ui = models.normalizeModelUIName(self.model)
  947.         self.model = models.normalizeModelName(self.model)
  948.  
  949.         log.debug("Model/UI model: %s/%s" % (self.model, self.model_ui))
  950.  
  951.         # TODO:
  952.         #service.setAlertsEx(self.hpssd_sock)
  953.  
  954.         self.mq = {} # Model query
  955.         self.dq = {} # Device query
  956.         self.icon = "default_printer"
  957.         self.cups_printers = []
  958.         self.channels = {} # { 'SERVICENAME' : channel_id, ... }
  959.         self.device_id = -1
  960.         self.r_values = None # ( r_value, r_value_str, rg, rr )
  961.         self.deviceID = ''
  962.         self.panel_check = True
  963.         self.io_state = IO_STATE_HP_READY
  964.         self.is_local = isLocal(self.bus)
  965.  
  966.         self.supported = False
  967.  
  968.         self.queryModel()
  969.         if not self.supported:
  970.             log.error("Unsupported model: %s" % self.model)
  971.             self.sendEvent(STATUS_DEVICE_UNSUPPORTED)
  972.         else:
  973.             self.supported = True
  974.  
  975.  
  976.         self.mq.update({'model'    : self.model,
  977.                         'model-ui' : self.model_ui})
  978.  
  979.         self.error_state = ERROR_STATE_ERROR
  980.         self.device_state = DEVICE_STATE_NOT_FOUND
  981.         self.status_code = EVENT_ERROR_DEVICE_NOT_FOUND
  982.  
  983.         for p in printers:
  984.             if self.device_uri == p.device_uri:
  985.                 self.cups_printers.append(p.name)
  986.                 self.state = p.state # ?
  987.  
  988.                 if self.io_state == IO_STATE_NON_HP:
  989.                     self.model = p.makemodel.split(',')[0]
  990.  
  991.         try:
  992.             self.first_cups_printer = self.cups_printers[0]
  993.         except IndexError:
  994.             self.first_cups_printer = ''
  995.  
  996.         if self.mq.get('fax-type', FAX_TYPE_NONE) != FAX_TYPE_NONE:
  997.             self.dq.update({ 'fax-uri' : self.device_uri.replace('hp:/', 'hpfax:/').replace('hpaio:/', 'hpfax:/')})
  998.  
  999.         if self.mq.get('scan-type', SCAN_TYPE_NONE) != SCAN_TYPE_NONE:
  1000.             self.dq.update({ 'scan-uri' : self.device_uri.replace('hp:/', 'hpaio:/').replace('hpfax:/', 'hpaio:/')})
  1001.  
  1002.         self.dq.update({
  1003.             'back-end'         : self.back_end,
  1004.             'is-hp'            : self.is_hp,
  1005.             'serial'           : self.serial,
  1006.             'dev-file'         : self.dev_file,
  1007.             'host'             : self.host,
  1008.             'port'             : self.port,
  1009.             'cups-printer'     : ','.join(self.cups_printers),
  1010.             'status-code'      : self.status_code,
  1011.             'status-desc'      : '',
  1012.             'deviceid'         : '',
  1013.             'panel'            : 0,
  1014.             'panel-line1'      : '',
  1015.             'panel-line2'      : '',
  1016.             'device-state'     : self.device_state,
  1017.             'error-state'      : self.error_state,
  1018.             'device-uri'       : self.device_uri,
  1019.             'cups-uri'         : self.device_uri.replace('hpfax:/', 'hp:/').replace('hpaio:/', 'hp:/'),
  1020.             })
  1021.  
  1022.         self.device_vars = {
  1023.             'URI'        : self.device_uri,
  1024.             'DEVICE_URI' : self.device_uri,
  1025.             'SCAN_URI'   : self.device_uri.replace('hp:', 'hpaio:'),
  1026.             'SANE_URI'   : self.device_uri.replace('hp:', 'hpaio:'),
  1027.             'FAX_URI'    : self.device_uri.replace('hp:', 'hpfax:'),
  1028.             'PRINTER'    : self.first_cups_printer,
  1029.             'HOME'       : prop.home_dir,
  1030.                            }
  1031.  
  1032.  
  1033.  
  1034.  
  1035.     def sendEvent(self, event_code, printer_name='', job_id=0, title=''):
  1036.         if self.dbus_avail:
  1037.             try:
  1038.                 self.service.SendEvent(self.device_uri, printer_name, event_code, prop.username, job_id, title)
  1039.             except dbus.exceptions.DBusException, e:
  1040.                 log.debug("dbus call to SendEvent() failed.")
  1041.  
  1042.  
  1043.     def quit(self):
  1044.         pass
  1045.  
  1046.  
  1047.     def queryModel(self):
  1048.         if not self.mq:
  1049.             self.mq = queryModelByURI(self.device_uri)
  1050.  
  1051.         self.supported = bool(self.mq)
  1052.  
  1053.         if self.supported:
  1054.             for m in self.mq:
  1055.                 self.__dict__[m.replace('-','_')] = self.mq[m]
  1056.  
  1057.  
  1058.     def queryString(self, string_id):
  1059.         return queryString(string_id)
  1060.  
  1061.  
  1062.     def open(self, open_for_printing=False):
  1063.         if self.supported and self.io_state in (IO_STATE_HP_READY, IO_STATE_HP_NOT_AVAIL):
  1064.             prev_device_state = self.device_state
  1065.             self.io_state = IO_STATE_HP_NOT_AVAIL
  1066.             self.device_state = DEVICE_STATE_NOT_FOUND
  1067.             self.error_state = ERROR_STATE_ERROR
  1068.             self.status_code = EVENT_ERROR_DEVICE_NOT_FOUND
  1069.             self.device_id = -1
  1070.             self.open_for_printing = open_for_printing
  1071.  
  1072.             if open_for_printing:
  1073.                 log.debug("Opening device: %s (for printing)" % self.device_uri)
  1074.                 self.io_mode = self.mq.get('io-mode', hpmudext.HPMUD_UNI_MODE)
  1075.             else:
  1076.                 log.debug("Opening device: %s (not for printing)" % self.device_uri)
  1077.                 self.io_mode = self.mq.get('io-mfp-mode', hpmudext.HPMUD_UNI_MODE)
  1078.  
  1079.             log.debug("I/O mode=%d" % self.io_mode)
  1080.             result_code, self.device_id = \
  1081.                 hpmudext.open_device(self.device_uri, self.io_mode)
  1082.  
  1083.             if result_code != hpmudext.HPMUD_R_OK:
  1084.                 self.error_state = ERROR_STATE_ERROR
  1085.                 self.sendEvent(result_code+ERROR_CODE_BASE)
  1086.                 
  1087.                 if result_code == hpmudext.HPMUD_R_DEVICE_BUSY:
  1088.                     log.error("Device busy: %s" % self.device_uri)
  1089.                 else:
  1090.                     log.error("Unable to communicate with device (code=%d): %s" % (result_code, self.device_uri))
  1091.  
  1092.                 self.last_event = Event(self.device_uri, '', EVENT_ERROR_DEVICE_NOT_FOUND,
  1093.                         prop.username, 0, '', time.time())
  1094.                 
  1095.                 raise Error(ERROR_DEVICE_NOT_FOUND)
  1096.  
  1097.             else:
  1098.                 log.debug("device-id=%d" % self.device_id)
  1099.                 self.io_state = IO_STATE_HP_OPEN
  1100.                 self.error_state = ERROR_STATE_CLEAR
  1101.                 log.debug("Opened device: %s (backend=%s, is_hp=%s, bus=%s, model=%s, dev=%s, serial=%s, host=%s, port=%d)" %
  1102.                     (self.back_end, self.device_uri, self.is_hp, self.bus, self.model,
  1103.                      self.dev_file, self.serial, self.host, self.port))
  1104.  
  1105.                 if prev_device_state == DEVICE_STATE_NOT_FOUND:
  1106.                     self.device_state = DEVICE_STATE_JUST_FOUND
  1107.                 else:
  1108.                     self.device_state = DEVICE_STATE_FOUND
  1109.  
  1110.                 self.getDeviceID()
  1111.                 self.getSerialNumber()
  1112.                 return self.device_id
  1113.  
  1114.  
  1115.  
  1116.     def close(self):
  1117.         if self.io_state == IO_STATE_HP_OPEN:
  1118.             log.debug("Closing device...")
  1119.  
  1120.             if len(self.channels) > 0:
  1121.  
  1122.                 for c in self.channels.keys():
  1123.                     self.__closeChannel(c)
  1124.  
  1125.             result_code = hpmudext.close_device(self.device_id)
  1126.             log.debug("Result-code = %d" % result_code)
  1127.  
  1128.             self.channels.clear()
  1129.             self.io_state = IO_STATE_HP_READY
  1130.  
  1131.  
  1132.     def __openChannel(self, service_name):
  1133.         if self.io_state == IO_STATE_HP_OPEN:
  1134.             if service_name == hpmudext.HPMUD_S_PRINT_CHANNEL and not self.open_for_printing:
  1135.                 self.close()
  1136.                 self.open(True)
  1137.             elif service_name != hpmudext.HPMUD_S_PRINT_CHANNEL and self.open_for_printing:
  1138.                 self.close()
  1139.                 self.open(False)
  1140.         else:
  1141.             self.open(service_name == hpmudext.HPMUD_S_PRINT_CHANNEL)
  1142.  
  1143.         #if not self.mq['io-mode'] == IO_MODE_UNI:
  1144.         if 1:
  1145.             service_name = service_name.upper()
  1146.  
  1147.             if service_name not in self.channels:
  1148.                 log.debug("Opening %s channel..." % service_name)
  1149.  
  1150.                 result_code, channel_id = hpmudext.open_channel(self.device_id, service_name)
  1151.  
  1152.                 self.channels[service_name] = channel_id
  1153.                 log.debug("channel-id=%d" % channel_id)
  1154.                 return channel_id
  1155.             else:
  1156.                 return self.channels[service_name]
  1157.         else:
  1158.             return -1
  1159.  
  1160.  
  1161.     def openChannel(self, service_name):
  1162.         return self.__openChannel(service_name)
  1163.  
  1164.     def openPrint(self):
  1165.         return self.__openChannel(hpmudext.HPMUD_S_PRINT_CHANNEL)
  1166.  
  1167.     def openFax(self):
  1168.         return self.__openChannel(hpmudext.HPMUD_S_FAX_SEND_CHANNEL)
  1169.  
  1170.     def openPCard(self):
  1171.         return self.__openChannel(hpmudext.HPMUD_S_MEMORY_CARD_CHANNEL)
  1172.  
  1173.     def openEWS(self):
  1174.         return self.__openChannel(hpmudext.HPMUD_S_EWS_CHANNEL)
  1175.  
  1176.     def closePrint(self):
  1177.         return self.__closeChannel(hpmudext.HPMUD_S_PRINT_CHANNEL)
  1178.  
  1179.     def closePCard(self):
  1180.         return self.__closeChannel(hpmudext.HPMUD_S_MEMORY_CARD_CHANNEL)
  1181.  
  1182.     def closeFax(self):
  1183.         return self.__closeChannel(hpmudext.HPMUD_S_FAX_SEND_CHANNEL)
  1184.  
  1185.     def openPML(self):
  1186.         return self.__openChannel(hpmudext.HPMUD_S_PML_CHANNEL)
  1187.  
  1188.     def closePML(self):
  1189.         return self.__closeChannel(hpmudext.HPMUD_S_PML_CHANNEL)
  1190.  
  1191.     def closeEWS(self):
  1192.         return self.__closeChannel(hpmudext.HPMUD_S_EWS_CHANNEL)
  1193.  
  1194.     def openCfgUpload(self):
  1195.         return self.__openChannel(hpmudext.HPMUD_S_CONFIG_UPLOAD_CHANNEL)
  1196.  
  1197.     def closeCfgUpload(self):
  1198.         return self.__closeChannel(hpmudext.HPMUD_S_CONFIG_UPLOAD_CHANNEL)
  1199.  
  1200.     def openCfgDownload(self):
  1201.         return self.__openChannel(hpmudext.HPMUD_S_CONFIG_DOWNLOAD_CHANNEL)
  1202.  
  1203.     def closeCfgDownload(self):
  1204.         return self.__closeChannel(hpmudext.HPMUD_S_CONFIG_DOWNLOAD_CHANNEL)
  1205.  
  1206.     def openSoapFax(self):
  1207.         return self.__openChannel(hpmudext.HPMUD_S_SOAP_FAX)
  1208.  
  1209.     def closeSoapFax(self):
  1210.         return self.__closeChannel(hpmudext.HPMUD_S_SOAP_FAX)
  1211.  
  1212.     def __closeChannel(self, service_name):
  1213.         #if not self.mq['io-mode'] == IO_MODE_UNI and \
  1214.         if self.io_state == IO_STATE_HP_OPEN:
  1215.  
  1216.             service_name = service_name.upper()
  1217.  
  1218.             if service_name in self.channels:
  1219.                 log.debug("Closing %s channel..." % service_name)
  1220.  
  1221.                 result_code = hpmudext.close_channel(self.device_id,
  1222.                     self.channels[service_name])
  1223.  
  1224.                 del self.channels[service_name]
  1225.  
  1226.  
  1227.     def closeChannel(self, service_name):
  1228.         return self.__closeChannel(service_name)
  1229.  
  1230.  
  1231.     def getDeviceID(self):
  1232.         needs_close = False
  1233.         if self.io_state != IO_STATE_HP_OPEN:
  1234.            self.open()
  1235.            needs_close = True
  1236.  
  1237.         result_code, data = hpmudext.get_device_id(self.device_id)
  1238.  
  1239.         if result_code != hpmudext.HPMUD_R_OK:
  1240.             self.raw_deviceID = ''
  1241.             self.deviceID = {}
  1242.         else:
  1243.             self.raw_deviceID = data
  1244.             self.deviceID = parseDeviceID(data)
  1245.  
  1246.         if needs_close:
  1247.             self.close()
  1248.  
  1249.         return self.deviceID
  1250.  
  1251.  
  1252.     def getSerialNumber(self):
  1253.         if self.serial:
  1254.             return
  1255.  
  1256.         try:
  1257.             self.serial = self.deviceID['SN']
  1258.         except KeyError:
  1259.             pass
  1260.         else:
  1261.             if self.serial:
  1262.                 return
  1263.  
  1264.         if self.mq.get('status-type', STATUS_TYPE_NONE) != STATUS_TYPE_NONE: # and \
  1265.             #not self.mq.get('io-mode', IO_MODE_UNI) == IO_MODE_UNI:
  1266.  
  1267.             try:
  1268.                 try:
  1269.                     error_code, self.serial = self.getPML(pml.OID_SERIAL_NUMBER)
  1270.                 except Error:
  1271.                     self.serial = ''
  1272.             finally:
  1273.                 self.closePML()
  1274.  
  1275.         if self.serial is None:
  1276.             self.serial = ''
  1277.  
  1278.  
  1279.     def getThreeBitStatus(self):
  1280.         pass
  1281.  
  1282.  
  1283.     def getStatusFromDeviceID(self):
  1284.         self.getDeviceID()
  1285.         return status.parseStatus(parseDeviceID(self.raw_deviceID))
  1286.  
  1287.  
  1288.     def __parseRValues(self, r_value):
  1289.         r_value_str = str(r_value)
  1290.         r_value_str = ''.join(['0'*(9 - len(r_value_str)), r_value_str])
  1291.         rg, rr = r_value_str[:3], r_value_str[3:]
  1292.         r_value = int(rr)
  1293.         self.r_values = r_value, r_value_str, rg, rr
  1294.         return r_value, r_value_str, rg, rr
  1295.  
  1296.  
  1297.     def getRValues(self, r_type, status_type, dynamic_counters):
  1298.         r_value, r_value_str, rg, rr = 0, '000000000', '000', '000000'
  1299.  
  1300.         if r_type > 0 and \
  1301.             dynamic_counters != STATUS_DYNAMIC_COUNTERS_NONE:
  1302.  
  1303.             if self.r_values is None:
  1304.                 if self.dbus_avail:
  1305.                     try:
  1306.                         r_value = int(self.service.GetCachedIntValue(self.device_uri, 'r_value'))
  1307.                     except dbus.exceptions.DBusException, e:
  1308.                         log.debug("dbus call to GetCachedIntValue() failed.")
  1309.                         r_value = -1
  1310.  
  1311.                 if r_value != -1:
  1312.                     log.debug("r_value=%d" % r_value)
  1313.                     r_value, r_value_str, rg, rr = self.__parseRValues(r_value)
  1314.  
  1315.                     return r_value, r_value_str, rg, rr
  1316.  
  1317.             if self.r_values is None:
  1318.  
  1319.                 if status_type ==  STATUS_TYPE_S and \
  1320.                     self.is_local and \
  1321.                     dynamic_counters != STATUS_DYNAMIC_COUNTERS_PML_SNMP:
  1322.  
  1323.                     try:
  1324.                         try:
  1325.                             r_value = self.getDynamicCounter(140)
  1326.  
  1327.                             if r_value is not None:
  1328.                                 log.debug("r_value=%d" % r_value)
  1329.                                 r_value, r_value_str, rg, rr = self.__parseRValues(r_value)
  1330.  
  1331.                                 if self.dbus_avail:
  1332.                                     try:
  1333.                                         self.service.SetCachedIntValue(self.device_uri, 'r_value', r_value)
  1334.                                     except dbus.exceptions.DBusException, e:
  1335.                                         log.debug("dbus call to SetCachedIntValue() failed.")
  1336.                             else:
  1337.                                 log.error("Error attempting to read r-value (2).")
  1338.                                 r_value = 0
  1339.                         except Error:
  1340.                             log.error("Error attempting to read r-value (1).")
  1341.                             r_value = 0
  1342.                     finally:
  1343.                         self.closePrint()
  1344.  
  1345.  
  1346.                 elif (status_type ==  STATUS_TYPE_S and
  1347.                       dynamic_counters == STATUS_DYNAMIC_COUNTERS_PCL and
  1348.                       not self.is_local) or \
  1349.                       dynamic_counters == STATUS_DYNAMIC_COUNTERS_PML_SNMP:
  1350.  
  1351.                     try:
  1352.                         result_code, r_value = self.getPML(pml.OID_R_SETTING)
  1353.  
  1354.                         if r_value is not None:
  1355.                             log.debug("r_value=%d" % r_value)
  1356.                             r_value, r_value_str, rg, rr = self.__parseRValues(r_value)
  1357.  
  1358.                             if self.dbus_avail:
  1359.                                 try:
  1360.                                     self.service.SetCachedIntValue(self.device_uri, 'r_value', r_value)
  1361.                                 except dbus.exceptions.DBusException, e:
  1362.                                     log.debug("dbus call to SetCachedIntValue() failed.")
  1363.  
  1364.                         else:
  1365.                             r_value = 0
  1366.  
  1367.                     finally:
  1368.                         self.closePML()
  1369.  
  1370.             else:
  1371.                 r_value, r_value_str, rg, rr = self.r_values
  1372.  
  1373.         return r_value, r_value_str, rg, rr
  1374.     
  1375.     
  1376.     def __queryFax(self, quick=False, reread_cups_printers=False):
  1377.         io_mode = self.mq.get('io-mode', IO_MODE_UNI)
  1378.         self.status_code = STATUS_PRINTER_IDLE
  1379.         
  1380.         if io_mode != IO_MODE_UNI:
  1381.         
  1382.             if self.device_state != DEVICE_STATE_NOT_FOUND:
  1383.                 if self.tech_type in (TECH_TYPE_MONO_INK, TECH_TYPE_COLOR_INK):
  1384.                     try:
  1385.                         self.getDeviceID()
  1386.                     except Error, e:
  1387.                         log.error("Error getting device ID.")
  1388.                         self.last_event = Event(self.device_uri, '', ERROR_DEVICE_IO_ERROR,
  1389.                             prop.username, 0, '', time.time())
  1390.                         
  1391.                         raise Error(ERROR_DEVICE_IO_ERROR)
  1392.  
  1393.                 status_desc = self.queryString(self.status_code)
  1394.  
  1395.                 #print self.status_code
  1396.                 
  1397.                 self.dq.update({
  1398.                     'serial'           : self.serial,
  1399.                     'cups-printer'     : ','.join(self.cups_printers),
  1400.                     'status-code'      : self.status_code,
  1401.                     'status-desc'      : status_desc,
  1402.                     'deviceid'         : self.raw_deviceID,
  1403.                     'panel'            : 0,
  1404.                     'panel-line1'      : '',
  1405.                     'panel-line2'      : '',
  1406.                     'device-state'     : self.device_state,
  1407.                     'error-state'      : self.error_state,
  1408.                     })
  1409.  
  1410.     
  1411.             log.debug("Fax activity check...")
  1412.  
  1413.             tx_active, rx_active = status.getFaxStatus(self)
  1414.  
  1415.             if tx_active:
  1416.                 self.status_code = STATUS_FAX_TX_ACTIVE
  1417.             elif rx_active:
  1418.                 self.status_code = STATUS_FAX_RX_ACTIVE
  1419.                 
  1420.             #print self.status_code                
  1421.             
  1422.             self.error_state = STATUS_TO_ERROR_STATE_MAP.get(self.status_code, ERROR_STATE_CLEAR)
  1423.             self.sendEvent(self.status_code)
  1424.             
  1425.             #print "Error state=", self.error_state, self.device_uri
  1426.  
  1427.             try:
  1428.                 self.dq.update({'status-desc' : self.queryString(self.status_code),
  1429.                                 'error-state' : self.error_state,
  1430.                                 })
  1431.  
  1432.             except (KeyError, Error):
  1433.                 self.dq.update({'status-desc' : '',
  1434.                                 'error-state' : ERROR_STATE_CLEAR,
  1435.                                 })
  1436.                                 
  1437.                                 
  1438.             if self.panel_check:
  1439.                 self.panel_check = bool(self.mq.get('panel-check-type', 0))
  1440.             
  1441.             status_type = self.mq.get('status-type', STATUS_TYPE_NONE)
  1442.             if self.panel_check and \
  1443.                 status_type in (STATUS_TYPE_LJ, STATUS_TYPE_S, STATUS_TYPE_VSTATUS) and \
  1444.                 io_mode != IO_MODE_UNI:
  1445.  
  1446.                 log.debug("Panel check...")
  1447.                 try:
  1448.                     self.panel_check, line1, line2 = status.PanelCheck(self)
  1449.                 finally:
  1450.                     self.closePML()
  1451.  
  1452.                 self.dq.update({'panel': int(self.panel_check),
  1453.                                   'panel-line1': line1,
  1454.                                   'panel-line2': line2,}) 
  1455.    
  1456.             if not quick and reread_cups_printers:
  1457.                 self.cups_printers = []
  1458.                 log.debug("Re-reading CUPS printer queue information.")
  1459.                 printers = cups.getPrinters()
  1460.                 for p in printers:
  1461.                     if self.device_uri == p.device_uri:
  1462.                         self.cups_printers.append(p.name)
  1463.                         self.state = p.state # ?
  1464.  
  1465.                         if self.io_state == IO_STATE_NON_HP:
  1466.                             self.model = p.makemodel.split(',')[0]
  1467.  
  1468.                 self.dq.update({'cups-printer' : ','.join(self.cups_printers)})
  1469.  
  1470.                 try:
  1471.                     self.first_cups_printer = self.cups_printers[0]
  1472.                 except IndexError:
  1473.                     self.first_cups_printer = ''
  1474.                                 
  1475.                                 
  1476.         for d in self.dq:
  1477.             self.__dict__[d.replace('-','_')] = self.dq[d]
  1478.  
  1479.         self.last_event = Event(self.device_uri, '', self.status_code, prop.username, 0, '', time.time())
  1480.         #print self.last_event
  1481.         
  1482.         log.debug(self.dq)
  1483.         
  1484.         #import pprint
  1485.         
  1486.         #pprint.pprint(self.dq)
  1487.                                 
  1488.                         
  1489.                         
  1490.         
  1491.     def queryDevice(self, quick=False, reread_cups_printers=False):
  1492.         if not self.supported:
  1493.             self.dq = {}
  1494.  
  1495.             self.last_event = Event(self.device_uri, '', STATUS_DEVICE_UNSUPPORTED,
  1496.                 prop.username, 0, '', time.time())
  1497.  
  1498.             return
  1499.             
  1500.         if self.device_type == DEVICE_TYPE_FAX:
  1501.             return self.__queryFax(quick, reread_cups_printers)
  1502.  
  1503.         r_type = self.mq.get('r-type', 0)
  1504.         tech_type = self.mq.get('tech-type', TECH_TYPE_NONE)
  1505.         status_type = self.mq.get('status-type', STATUS_TYPE_NONE)
  1506.         battery_check = self.mq.get('status-battery-check', STATUS_BATTERY_CHECK_NONE)
  1507.         dynamic_counters = self.mq.get('status-dynamic-counters', STATUS_DYNAMIC_COUNTERS_NONE)
  1508.         io_mode = self.mq.get('io-mode', IO_MODE_UNI)
  1509.         io_mfp_mode = self.mq.get('io-mfp-mode', IO_MODE_UNI)
  1510.         status_code = STATUS_UNKNOWN
  1511.  
  1512.         # Turn off status if local connection and bi-di not avail.
  1513.         #if io_mode  == IO_MODE_UNI and self.back_end != 'net':
  1514.         #    status_type = STATUS_TYPE_NONE
  1515.  
  1516.         agents = []
  1517.  
  1518.         if self.device_state != DEVICE_STATE_NOT_FOUND:
  1519.             if self.tech_type in (TECH_TYPE_MONO_INK, TECH_TYPE_COLOR_INK):
  1520.                 try:
  1521.                     self.getDeviceID()
  1522.                 except Error, e:
  1523.                     log.error("Error getting device ID.")
  1524.                     self.last_event = Event(self.device_uri, '', ERROR_DEVICE_IO_ERROR,
  1525.                         prop.username, 0, '', time.time())
  1526.                     
  1527.                     raise Error(ERROR_DEVICE_IO_ERROR)
  1528.  
  1529.             status_desc = self.queryString(self.status_code)
  1530.  
  1531.             self.dq.update({
  1532.                 'serial'           : self.serial,
  1533.                 'cups-printer'     : ','.join(self.cups_printers),
  1534.                 'status-code'      : self.status_code,
  1535.                 'status-desc'      : status_desc,
  1536.                 'deviceid'         : self.raw_deviceID,
  1537.                 'panel'            : 0,
  1538.                 'panel-line1'      : '',
  1539.                 'panel-line2'      : '',
  1540.                 'device-state'     : self.device_state,
  1541.                 'error-state'      : self.error_state,
  1542.                 })
  1543.  
  1544.             status_block = {}
  1545.  
  1546.             if status_type == STATUS_TYPE_NONE:
  1547.                 log.warn("No status available for device.")
  1548.                 status_block = {'status-code' : STATUS_UNKNOWN}
  1549.  
  1550.             elif status_type in (STATUS_TYPE_VSTATUS, STATUS_TYPE_S):
  1551.                 log.debug("Type 1/2 (S: or VSTATUS:) status")
  1552.                 status_block = status.parseStatus(self.deviceID)
  1553.  
  1554.             elif status_type in (STATUS_TYPE_LJ, STATUS_TYPE_PML_AND_PJL):
  1555.                 log.debug("Type 3/9 LaserJet PML(+PJL) status")
  1556.                 status_block = status.StatusType3(self, self.deviceID)
  1557.  
  1558.             elif status_type == STATUS_TYPE_LJ_XML:
  1559.                 log.debug("Type 6: LJ XML")
  1560.                 status_block = status.StatusType6(self)
  1561.  
  1562.             elif status_type == STATUS_TYPE_PJL:
  1563.                 log.debug("Type 8: LJ PJL")
  1564.                 status_block = status.StatusType8(self)
  1565.  
  1566.             else:
  1567.                 log.error("Unimplemented status type: %d" % status_type)
  1568.  
  1569.             if battery_check and \
  1570.                 io_mode != IO_MODE_UNI:
  1571.  
  1572.                 log.debug("Battery check...")
  1573.                 status.BatteryCheck(self, status_block, battery_check)
  1574.  
  1575.             if status_block:
  1576.                 log.debug(status_block)
  1577.                 self.dq.update(status_block)
  1578.                 try:
  1579.                     status_block['agents']
  1580.                 except KeyError:
  1581.                     pass
  1582.                 else:
  1583.                     agents = status_block['agents']
  1584.                     del self.dq['agents']
  1585.  
  1586.  
  1587.             status_code = self.dq.get('status-code', STATUS_UNKNOWN)
  1588.  
  1589. ##            if not quick and \
  1590. ##                self.mq.get('fax-type', FAX_TYPE_NONE) and \
  1591. ##                status_code == STATUS_PRINTER_IDLE and \
  1592. ##                io_mode != IO_MODE_UNI:
  1593. ##
  1594. ##                log.debug("Fax activity check...")
  1595. ##
  1596. ##                tx_active, rx_active = status.getFaxStatus(self)
  1597. ##
  1598. ##                if tx_active:
  1599. ##                    status_code = STATUS_FAX_TX_ACTIVE
  1600. ##                elif rx_active:
  1601. ##                    status_code = STATUS_FAX_RX_ACTIVE
  1602.  
  1603.  
  1604.             self.error_state = STATUS_TO_ERROR_STATE_MAP.get(status_code, ERROR_STATE_CLEAR)
  1605.             self.sendEvent(status_code)
  1606.             
  1607.             #print "Error state=", self.error_state, self.device_uri
  1608.  
  1609.             try:
  1610.                 self.dq.update({'status-desc' : self.queryString(status_code),
  1611.                                 'error-state' : self.error_state,
  1612.                                 })
  1613.  
  1614.             except (KeyError, Error):
  1615.                 self.dq.update({'status-desc' : '',
  1616.                                 'error-state' : ERROR_STATE_CLEAR,
  1617.                                 })
  1618.  
  1619.             r_value = 0
  1620.  
  1621.             if not quick and status_type != STATUS_TYPE_NONE:
  1622.                 if self.panel_check:
  1623.                     self.panel_check = bool(self.mq.get('panel-check-type', 0))
  1624.  
  1625.                 if self.panel_check and \
  1626.                     status_type in (STATUS_TYPE_LJ, STATUS_TYPE_S, STATUS_TYPE_VSTATUS) and \
  1627.                     io_mode != IO_MODE_UNI:
  1628.  
  1629.                     log.debug("Panel check...")
  1630.                     try:
  1631.                         self.panel_check, line1, line2 = status.PanelCheck(self)
  1632.                     finally:
  1633.                         self.closePML()
  1634.  
  1635.                     self.dq.update({'panel': int(self.panel_check),
  1636.                                       'panel-line1': line1,
  1637.                                       'panel-line2': line2,})
  1638.  
  1639.  
  1640.                 if dynamic_counters != STATUS_DYNAMIC_COUNTERS_NONE and \
  1641.                     io_mode != IO_MODE_UNI:
  1642.  
  1643.                     r_value, r_value_str, rg, rr = self.getRValues(r_type, status_type, dynamic_counters)
  1644.                 else:
  1645.                     r_value, r_value_str, rg, rr = 0, '000000000', '000', '000000'
  1646.  
  1647.                 self.dq.update({'r'  : r_value,
  1648.                                 'rs' : r_value_str,
  1649.                                 'rg' : rg,
  1650.                                 'rr' : rr,
  1651.                               })
  1652.  
  1653.             if not quick and reread_cups_printers:
  1654.                 self.cups_printers = []
  1655.                 log.debug("Re-reading CUPS printer queue information.")
  1656.                 printers = cups.getPrinters()
  1657.                 for p in printers:
  1658.                     if self.device_uri == p.device_uri:
  1659.                         self.cups_printers.append(p.name)
  1660.                         self.state = p.state # ?
  1661.  
  1662.                         if self.io_state == IO_STATE_NON_HP:
  1663.                             self.model = p.makemodel.split(',')[0]
  1664.  
  1665.                 self.dq.update({'cups-printer' : ','.join(self.cups_printers)})
  1666.  
  1667.                 try:
  1668.                     self.first_cups_printer = self.cups_printers[0]
  1669.                 except IndexError:
  1670.                     self.first_cups_printer = ''
  1671.  
  1672.             if not quick:
  1673.                 # Make sure there is some valid agent data for this r_value
  1674.                 # If not, fall back to r_value == 0
  1675.                 if r_value > 0 and self.mq.get('r%d-agent1-kind' % r_value, 0) == 0:
  1676.                     r_value = 0
  1677.                     self.dq.update({'r'  : r_value,
  1678.                                     'rs' : r_value_str,
  1679.                                     'rg' : rg,
  1680.                                     'rr' : rr,
  1681.                                   })
  1682.  
  1683.                 a, aa = 1, 1
  1684.                 while True:
  1685.                     mq_agent_kind = self.mq.get('r%d-agent%d-kind' % (r_value, a), -1)
  1686.  
  1687.                     if mq_agent_kind == -1:
  1688.                         break
  1689.  
  1690.                     mq_agent_type = self.mq.get('r%d-agent%d-type' % (r_value, a), 0)
  1691.                     mq_agent_sku = self.mq.get('r%d-agent%d-sku' % (r_value, a), '')
  1692.  
  1693.                     found = False
  1694.  
  1695.                     log.debug("Looking for kind=%d, type=%d..." % (mq_agent_kind, mq_agent_type))
  1696.                     for agent in agents:
  1697.                         agent_kind = agent['kind']
  1698.                         agent_type = agent['type']
  1699.  
  1700.                         if agent_kind == mq_agent_kind and \
  1701.                            agent_type == mq_agent_type:
  1702.                            found = True
  1703.                            break
  1704.  
  1705.                     if found:
  1706.                         log.debug("found: r%d-kind%d-type%d" % (r_value, agent_kind, agent_type))
  1707.  
  1708.                         agent_health = agent.get('health', AGENT_HEALTH_OK)
  1709.                         agent_level = agent.get('level', 100)
  1710.                         agent_level_trigger = agent.get('level-trigger',
  1711.                             AGENT_LEVEL_TRIGGER_SUFFICIENT_0)
  1712.  
  1713.                         log.debug("health=%d, level=%d, level_trigger=%d, status_code=%d" %
  1714.                             (agent_health, agent_level, agent_level_trigger, status_code))
  1715.  
  1716.                         query = 'agent_%s_%s' % (AGENT_types.get(agent_type, 'unknown'),
  1717.                                                  AGENT_kinds.get(agent_kind, 'unknown'))
  1718.  
  1719.                         agent_desc = self.queryString(query)
  1720.                         query = 'agent_health_ok'
  1721.  
  1722.                         # If printer is not in an error state, and
  1723.                         # if agent health is OK, check for low supplies. If low, use
  1724.                         # the agent level trigger description for the agent description.
  1725.                         # Otherwise, report the agent health.
  1726.                         if (status_code == STATUS_PRINTER_IDLE or status_code == STATUS_PRINTER_OUT_OF_INK) and \
  1727.                             (agent_health == AGENT_HEALTH_OK or
  1728.                              (agent_health == AGENT_HEALTH_FAIR_MODERATE and agent_kind == AGENT_KIND_HEAD)) and \
  1729.                             agent_level_trigger >= AGENT_LEVEL_TRIGGER_MAY_BE_LOW:
  1730.  
  1731.                             query = 'agent_level_%s' % AGENT_levels.get(agent_level_trigger, 'unknown')
  1732.  
  1733.                             if tech_type in (TECH_TYPE_MONO_INK, TECH_TYPE_COLOR_INK):
  1734.                                 code = agent_type + STATUS_PRINTER_LOW_INK_BASE
  1735.                             else:
  1736.                                 code = agent_type + STATUS_PRINTER_LOW_TONER_BASE
  1737.  
  1738.                             self.dq['status-code'] = code
  1739.                             self.dq['status-desc'] = self.queryString(code)
  1740.  
  1741.                             self.dq['error-state'] = STATUS_TO_ERROR_STATE_MAP.get(code, ERROR_STATE_LOW_SUPPLIES)
  1742.                             self.sendEvent(code)
  1743.  
  1744.                             if agent_level_trigger in \
  1745.                                 (AGENT_LEVEL_TRIGGER_PROBABLY_OUT, AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT):
  1746.  
  1747.                                 query = 'agent_level_out'
  1748.                             else:
  1749.                                 query = 'agent_level_low'
  1750.  
  1751.                             agent_health_desc = self.queryString(query)
  1752.  
  1753.                             self.dq.update(
  1754.                             {
  1755.                                 'agent%d-kind' % aa :          agent_kind,
  1756.                                 'agent%d-type' % aa :          agent_type,
  1757.                                 'agent%d-known' % aa :         agent.get('known', False),
  1758.                                 'agent%d-sku' % aa :           mq_agent_sku,
  1759.                                 'agent%d-level' % aa :         agent_level,
  1760.                                 'agent%d-level-trigger' % aa : agent_level_trigger,
  1761.                                 'agent%d-ack' % aa :           agent.get('ack', False),
  1762.                                 'agent%d-hp-ink' % aa :        agent.get('hp-ink', False),
  1763.                                 'agent%d-health' % aa :        agent_health,
  1764.                                 'agent%d-dvc' % aa :           agent.get('dvc', 0),
  1765.                                 'agent%d-virgin' % aa :        agent.get('virgin', False),
  1766.                                 'agent%d-desc' % aa :          agent_desc,
  1767.                                 'agent%d-id' % aa :            agent.get('id', 0),
  1768.                                 'agent%d-health-desc' % aa :   agent_health_desc,
  1769.                             })
  1770.  
  1771.                         else:
  1772.                             query = 'agent_health_%s' % AGENT_healths.get(agent_health, AGENT_HEALTH_OK)
  1773.                             agent_health_desc = self.queryString(query)
  1774.  
  1775.                             self.dq.update(
  1776.                             {
  1777.                                 'agent%d-kind' % aa :          agent_kind,
  1778.                                 'agent%d-type' % aa :          agent_type,
  1779.                                 'agent%d-known' % aa :         False,
  1780.                                 'agent%d-sku' % aa :           mq_agent_sku,
  1781.                                 'agent%d-level' % aa :         agent_level,
  1782.                                 'agent%d-level-trigger' % aa : agent_level_trigger,
  1783.                                 'agent%d-ack' % aa :           False,
  1784.                                 'agent%d-hp-ink' % aa :        False,
  1785.                                 'agent%d-health' % aa :        agent_health,
  1786.                                 'agent%d-dvc' % aa :           0,
  1787.                                 'agent%d-virgin' % aa :        False,
  1788.                                 'agent%d-desc' % aa :          agent_desc,
  1789.                                 'agent%d-id' % aa :            0,
  1790.                                 'agent%d-health-desc' % aa :   agent_health_desc,
  1791.                             })
  1792.                             
  1793.                         aa += 1
  1794.  
  1795.                     else:
  1796.                         log.debug("Not found: %d" % a)
  1797.                         
  1798.                     a += 1
  1799.  
  1800.         else: # Create agent keys for not-found devices
  1801.  
  1802.             r_value = 0
  1803.             if r_type > 0 and self.r_values is not None:
  1804.                 r_value = self.r_values[0]
  1805.  
  1806.             # Make sure there is some valid agent data for this r_value
  1807.             # If not, fall back to r_value == 0
  1808.             if r_value > 0 and self.mq.get('r%d-agent1-kind', 0) == 0:
  1809.                 r_value = 0
  1810.  
  1811.             a = 1
  1812.             while True:
  1813.                 mq_agent_kind = self.mq.get('r%d-agent%d-kind' % (r_value, a), 0)
  1814.  
  1815.                 if mq_agent_kind == 0:
  1816.                     break
  1817.  
  1818.                 mq_agent_type = self.mq.get('r%d-agent%d-type' % (r_value, a), 0)
  1819.                 mq_agent_sku = self.mq.get('r%d-agent%d-sku' % (r_value, a), '')
  1820.                 query = 'agent_%s_%s' % (AGENT_types.get(mq_agent_type, 'unknown'),
  1821.                                          AGENT_kinds.get(mq_agent_kind, 'unknown'))
  1822.  
  1823.                 agent_desc = self.queryString(query)
  1824.  
  1825.                 self.dq.update(
  1826.                 {
  1827.                     'agent%d-kind' % a :          mq_agent_kind,
  1828.                     'agent%d-type' % a :          mq_agent_type,
  1829.                     'agent%d-known' % a :         False,
  1830.                     'agent%d-sku' % a :           mq_agent_sku,
  1831.                     'agent%d-level' % a :         0,
  1832.                     'agent%d-level-trigger' % a : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  1833.                     'agent%d-ack' % a :           False,
  1834.                     'agent%d-hp-ink' % a :        False,
  1835.                     'agent%d-health' % a :        AGENT_HEALTH_MISINSTALLED,
  1836.                     'agent%d-dvc' % a :           0,
  1837.                     'agent%d-virgin' % a :        False,
  1838.                     'agent%d-health-desc' % a :   self.queryString('agent_health_unknown'),
  1839.                     'agent%d-desc' % a :          agent_desc,
  1840.                     'agent%d-id' % a :            0,
  1841.                 })
  1842.  
  1843.                 a += 1
  1844.  
  1845.         for d in self.dq:
  1846.             self.__dict__[d.replace('-','_')] = self.dq[d]
  1847.  
  1848.         self.last_event = Event(self.device_uri, '', status_code, prop.username, 0, '', time.time())
  1849.         log.debug(self.dq)
  1850.  
  1851.  
  1852.     def isBusyOrInErrorState(self):
  1853.         self.queryDevice(quick=True)
  1854.         return self.error_state > ERROR_STATE_MAX_OK
  1855.  
  1856.     def isIdleAndNoError(self):
  1857.         self.queryDevice(quick=True)
  1858.         #print self.error_state
  1859.         return self.error_state <= ERROR_STATE_MAX_OK
  1860.  
  1861.     def getPML(self, oid, desired_int_size=pml.INT_SIZE_INT): # oid => ( 'dotted oid value', pml type )
  1862.         channel_id = self.openPML()
  1863.  
  1864.         result_code, data, typ, pml_result_code = \
  1865.             hpmudext.get_pml(self.device_id, channel_id, pml.PMLToSNMP(oid[0]), oid[1])
  1866.  
  1867.         if pml_result_code > pml.ERROR_MAX_OK:
  1868.             log.debug("PML/SNMP GET %s failed (result code = 0x%x)" % (oid[0], pml_result_code))
  1869.             return pml_result_code, None
  1870.  
  1871.         converted_data = pml.ConvertFromPMLDataFormat(data, oid[1], desired_int_size)
  1872.  
  1873.         if log.is_debug():
  1874.             if oid[1] in (pml.TYPE_STRING, pml.TYPE_BINARY):
  1875.  
  1876.                 log.debug("PML/SNMP GET %s (result code = 0x%x) returned:" %
  1877.                     (oid[0], pml_result_code))
  1878.                 log.log_data(data)
  1879.             else:
  1880.                 log.debug("PML/SNMP GET %s (result code = 0x%x) returned: %s" %
  1881.                     (oid[0], pml_result_code, repr(converted_data)))
  1882.  
  1883.         return pml_result_code, converted_data
  1884.  
  1885.  
  1886.     def setPML(self, oid, value): # oid => ( 'dotted oid value', pml type )
  1887.         channel_id = self.openPML()
  1888.  
  1889.         value = pml.ConvertToPMLDataFormat(value, oid[1])
  1890.  
  1891.         result_code, pml_result_code = \
  1892.             hpmudext.set_pml(self.device_id, channel_id, pml.PMLToSNMP(oid[0]), oid[1], value)
  1893.  
  1894.         if log.is_debug():
  1895.             if oid[1] in (pml.TYPE_STRING, pml.TYPE_BINARY):
  1896.  
  1897.                 log.debug("PML/SNMP SET %s (result code = 0x%x) to:" %
  1898.                     (oid[0], pml_result_code))
  1899.                 log.log_data(value)
  1900.             else:
  1901.                 log.debug("PML/SNMP SET %s (result code = 0x%x) to: %s" %
  1902.                     (oid[0], pml_result_code, repr(value)))
  1903.  
  1904.         return pml_result_code
  1905.  
  1906.  
  1907.     def getDynamicCounter(self, counter, convert_to_int=True):
  1908.         dynamic_counters = self.mq.get('status-dynamic-counters', STATUS_DYNAMIC_COUNTERS_NONE)
  1909.         log.debug("Dynamic counters: %d" % dynamic_counters)
  1910.         if dynamic_counters != STATUS_DYNAMIC_COUNTERS_NONE:
  1911.  
  1912.             if dynamic_counters == STATUS_DYNAMIC_COUNTERS_LIDIL_0_5_4:
  1913.                 self.printData(ldl.buildResetPacket(), direct=True)
  1914.                 self.printData(ldl.buildDynamicCountersPacket(counter), direct=True)
  1915.             else:
  1916.                 self.printData(pcl.buildDynamicCounter(counter), direct=True)
  1917.  
  1918.             value, tries, times_seen, sleepy_time, max_tries = 0, 0, 0, 0.1, 5
  1919.             time.sleep(0.1)
  1920.  
  1921.             while True:
  1922.  
  1923.                 if self.callback:
  1924.                     self.callback()
  1925.  
  1926.                 sleepy_time += 0.1
  1927.                 tries += 1
  1928.  
  1929.                 time.sleep(sleepy_time)
  1930.  
  1931.                 self.getDeviceID()
  1932.  
  1933.                 if 'CTR' in self.deviceID and \
  1934.                     pat_dynamic_ctr.search(self.raw_deviceID) is not None:
  1935.                     dev_counter, value = parseDynamicCounter(self.deviceID['CTR'], convert_to_int)
  1936.  
  1937.                     if counter == dev_counter:
  1938.                         self.printData(pcl.buildDynamicCounter(0), direct=True)
  1939.                         # protect the value as a string during msg handling
  1940.                         if not convert_to_int:
  1941.                             value = '#' + value
  1942.                         return value
  1943.  
  1944.                 if tries > max_tries:
  1945.                     if dynamic_counters == STATUS_DYNAMIC_COUNTERS_LIDIL_0_5_4:
  1946.                         self.printData(ldl.buildResetPacket())
  1947.                         self.printData(ldl.buildDynamicCountersPacket(counter), direct=True)
  1948.                     else:
  1949.                         self.printData(pcl.buildDynamicCounter(0), direct=True)
  1950.  
  1951.                     return None
  1952.  
  1953.                 if dynamic_counters == STATUS_DYNAMIC_COUNTERS_LIDIL_0_5_4:
  1954.                     self.printData(ldl.buildResetPacket())
  1955.                     self.printData(ldl.buildDynamicCountersPacket(counter), direct=True)
  1956.                 else:
  1957.                     self.printData(pcl.buildDynamicCounter(counter), direct=True)
  1958.  
  1959.         else:
  1960.             raise Error(ERROR_DEVICE_DOES_NOT_SUPPORT_OPERATION)
  1961.  
  1962.  
  1963.     def readPrint(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  1964.         return self.__readChannel(self.openPrint, bytes_to_read, stream, timeout, allow_short_read)
  1965.  
  1966.     def readPCard(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  1967.         return self.__readChannel(self.openPCard, bytes_to_read, stream, timeout, allow_short_read)
  1968.  
  1969.     def readFax(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  1970.         return self.__readChannel(self.openFax, bytes_to_read, stream, timeout, allow_short_read)
  1971.  
  1972.     def readCfgUpload(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  1973.         return self.__readChannel(self.openCfgUpload, bytes_to_read, stream, timeout, allow_short_read)
  1974.  
  1975.     def readEWS(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=True):
  1976.         return self.__readChannel(self.openEWS, bytes_to_read, stream, timeout, allow_short_read)
  1977.  
  1978.     def readSoapFax(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=True):
  1979.         return self.__readChannel(self.openSoapFax, bytes_to_read, stream, timeout, allow_short_read)
  1980.  
  1981.     def __readChannel(self, opener, bytes_to_read, stream=None,
  1982.                       timeout=prop.read_timeout, allow_short_read=False):
  1983.  
  1984.         channel_id = opener()
  1985.  
  1986.         log.debug("Reading channel %d..." % channel_id)
  1987.  
  1988.         num_bytes = 0
  1989.  
  1990.         if stream is None:
  1991.             buffer = ''
  1992.  
  1993.         while True:
  1994.             result_code, data = \
  1995.                 hpmudext.read_channel(self.device_id, channel_id, bytes_to_read, timeout)
  1996.  
  1997.             l = len(data)
  1998.  
  1999.             if result_code == hpmudext.HPMUD_R_IO_TIMEOUT:
  2000.                 log.debug("I/O timeout")
  2001.                 break
  2002.  
  2003.             if result_code != hpmudext.HPMUD_R_OK:
  2004.                 log.error("Channel read error")
  2005.                 raise Error(ERROR_DEVICE_IO_ERROR)
  2006.  
  2007.             if not l:
  2008.                 log.debug("End of data")
  2009.                 break
  2010.  
  2011.             if stream is None:
  2012.                 buffer = ''.join([buffer, data])
  2013.             else:
  2014.                 stream.write(data)
  2015.  
  2016.             num_bytes += l
  2017.  
  2018.             if self.callback is not None:
  2019.                 self.callback()
  2020.  
  2021.             if num_bytes == bytes_to_read:
  2022.                 log.debug("Full read complete.")
  2023.                 break
  2024.  
  2025.             if allow_short_read and num_bytes < bytes_to_read:
  2026.                 log.debug("Allowed short read of %d of %d bytes complete." % (num_bytes, bytes_to_read))
  2027.                 break
  2028.  
  2029.         if stream is None:
  2030.             log.debug("Returned %d total bytes in buffer." % num_bytes)
  2031.             return buffer
  2032.         else:
  2033.             log.debug("Saved %d total bytes to stream." % num_bytes)
  2034.             return num_bytes
  2035.  
  2036.  
  2037.     def writePrint(self, data):
  2038.         return self.__writeChannel(self.openPrint, data)
  2039.  
  2040.     def writePCard(self, data):
  2041.         return self.__writeChannel(self.openPCard, data)
  2042.  
  2043.     def writeFax(self, data):
  2044.         return self.__writeChannel(self.openFax, data)
  2045.  
  2046.     def writeEWS(self, data):
  2047.         return self.__writeChannel(self.openEWS, data)
  2048.  
  2049.     def writeCfgDownload(self, data):
  2050.         return self.__writeChannel(self.openCfgDownload, data)
  2051.  
  2052.     def writeSoapFax(self, data):
  2053.         return self.__writeChannel(self.openSoapFax, data)
  2054.  
  2055.  
  2056.     def __writeChannel(self, opener, data):
  2057.         channel_id = opener()
  2058.  
  2059.         buffer, bytes_out, total_bytes_to_write = data, 0, len(data)
  2060.         log.debug("Writing %d bytes to channel %d..." % (total_bytes_to_write,channel_id))
  2061.  
  2062.         while len(buffer) > 0:
  2063.             result_code, bytes_written = \
  2064.                 hpmudext.write_channel(self.device_id, channel_id,
  2065.                     buffer[:prop.max_message_len])
  2066.  
  2067.             if result_code != hpmudext.HPMUD_R_OK:
  2068.                 log.error("Channel write error")
  2069.                 raise Error(ERROR_DEVICE_IO_ERROR)
  2070.  
  2071.             buffer = buffer[prop.max_message_len:]
  2072.             bytes_out += bytes_written
  2073.  
  2074.             if self.callback is not None:
  2075.                 self.callback()
  2076.  
  2077.         if total_bytes_to_write != bytes_out:
  2078.             raise Error(ERROR_DEVICE_IO_ERROR)
  2079.  
  2080.         return bytes_out
  2081.  
  2082.  
  2083.     def writeEmbeddedPML(self, oid, value, style=1, direct=True):
  2084.         if style == 1:
  2085.             func = pcl.buildEmbeddedPML2
  2086.         else:
  2087.             func = pcl.buildEmbeddedPML
  2088.  
  2089.         data = func(pcl.buildPCLCmd('&', 'b', 'W',
  2090.                      pml.buildEmbeddedPMLSetPacket(oid[0],
  2091.                                                     value,
  2092.                                                     oid[1])))
  2093.  
  2094.         log.log_data(data)
  2095.  
  2096.         self.printData(data, direct=direct, raw=True)
  2097.  
  2098.  
  2099.     def printGzipFile(self, file_name, printer_name=None, direct=False, raw=True, remove=False):
  2100.         return self.printFile(file_name, printer_name, direct, raw, remove)
  2101.  
  2102.     def printParsedGzipPostscript(self, print_file, printer_name=None):
  2103.         # always: direct=False, raw=False, remove=True
  2104.         try:
  2105.             os.stat(print_file)
  2106.         except OSError:
  2107.             log.error("File not found: %s" % print_file)
  2108.             return
  2109.  
  2110.         temp_file_fd, temp_file_name = utils.make_temp_file()
  2111.         f = gzip.open(print_file, 'r')
  2112.  
  2113.         x = f.readline()
  2114.         while not x.startswith('%PY_BEGIN'):
  2115.             os.write(temp_file_fd, x)
  2116.             x = f.readline()
  2117.  
  2118.         sub_lines = []
  2119.         x = f.readline()
  2120.         while not x.startswith('%PY_END'):
  2121.             sub_lines.append(x)
  2122.             x = f.readline()
  2123.  
  2124.         SUBS = {'VERSION' : prop.version,
  2125.                  'MODEL'   : self.model_ui,
  2126.                  'URI'     : self.device_uri,
  2127.                  'BUS'     : self.bus,
  2128.                  'SERIAL'  : self.serial,
  2129.                  'IP'      : self.host,
  2130.                  'PORT'    : self.port,
  2131.                  'DEVNODE' : self.dev_file,
  2132.                  }
  2133.  
  2134.         if self.bus == 'net':
  2135.             SUBS['DEVNODE'] = 'n/a'
  2136.         else:
  2137.             SUBS['IP'] = 'n/a'
  2138.             SUBS['PORT'] = 'n/a'
  2139.  
  2140.         for s in sub_lines:
  2141.             os.write(temp_file_fd, s % SUBS)
  2142.  
  2143.         os.write(temp_file_fd, f.read())
  2144.         f.close()
  2145.         os.close(temp_file_fd)
  2146.  
  2147.         self.printFile(temp_file_name, printer_name, direct=False, raw=False, remove=True)
  2148.  
  2149.     def printFile(self, file_name, printer_name=None, direct=False, raw=True, remove=False):
  2150.         is_gzip = os.path.splitext(file_name)[-1].lower() == '.gz'
  2151.  
  2152.         if printer_name is None:
  2153.             try:
  2154.                 printer_name = self.cups_printers[0]
  2155.             except IndexError:
  2156.                 raise Error(ERROR_NO_CUPS_QUEUE_FOUND_FOR_DEVICE)
  2157.  
  2158.         log.debug("Printing file '%s' to queue '%s' (gzip=%s, direct=%s, raw=%s, remove=%s)" %
  2159.                    (file_name, printer_name, is_gzip, direct, raw, remove))
  2160.  
  2161.         if direct: # implies raw==True
  2162.             if is_gzip:
  2163.                 self.writePrint(gzip.open(file_name, 'r').read())
  2164.             else:
  2165.                 self.writePrint(file(file_name, 'r').read())
  2166.  
  2167.         else:
  2168.             if not utils.which('lpr'):
  2169.                 lp_opt = ''
  2170.  
  2171.                 if raw:
  2172.                     lp_opt = '-oraw'
  2173.  
  2174.                 if is_gzip:
  2175.                     c = 'gunzip -c %s | lp -c -d%s %s' % (file_name, printer_name, lp_opt)
  2176.                 else:
  2177.                     c = 'lp -c -d%s %s %s' % (printer_name, lp_opt, file_name)
  2178.  
  2179.                 log.debug(c)
  2180.                 exit_code = os.system(c)
  2181.  
  2182.                 if exit_code != 0:
  2183.                     log.error("Print command failed with exit code %d!" % exit_code)
  2184.  
  2185.                 if remove:
  2186.                     os.remove(file_name)
  2187.  
  2188.             else:
  2189.                 raw_str, rem_str = '', ''
  2190.                 if raw: raw_str = '-o raw'
  2191.                 if remove: rem_str = '-r'
  2192.  
  2193.                 if is_gzip:
  2194.                     c = 'gunzip -c %s | lpr %s %s -P%s' % (file_name, raw_str, rem_str, printer_name)
  2195.                 else:
  2196.                     c = 'lpr -P%s %s %s %s' % (printer_name, raw_str, rem_str, file_name)
  2197.  
  2198.                 log.debug(c)
  2199.                 exit_code = os.system(c)
  2200.  
  2201.                 if exit_code != 0:
  2202.                     log.error("Print command failed with exit code %d!" % exit_code)
  2203.  
  2204.  
  2205.     def printTestPage(self, printer_name=None):
  2206.         return self.printParsedGzipPostscript(os.path.join( prop.home_dir, 'data',
  2207.                                               'ps', 'testpage.ps.gz' ), printer_name)
  2208.  
  2209.  
  2210.     def printData(self, data, printer_name=None, direct=True, raw=True):
  2211.         #log.log_data(data)
  2212.         #log.debug("printData(direct=%s, raw=%s)" % (direct, raw))
  2213.         if direct:
  2214.             self.writePrint(data)
  2215.         else:
  2216.             temp_file_fd, temp_file_name = utils.make_temp_file()
  2217.             os.write(temp_file_fd, data)
  2218.             os.close(temp_file_fd)
  2219.  
  2220.             self.printFile(temp_file_name, printer_name, False, raw, remove=True)
  2221.  
  2222.  
  2223.     def cancelJob(self, jobid):
  2224.         cups.cancelJob(jobid)
  2225.         self.sendEvent(STATUS_PRINTER_CANCELING)
  2226.  
  2227.  
  2228.     def queryHistory(self):
  2229.         result = []
  2230.  
  2231.         if self.dbus_avail:
  2232.             try:
  2233.                 history = list(self.service.GetHistory(self.device_uri))
  2234.             except dbus.exceptions.DBusException, e:
  2235.                 log.debug("dbus call to GetHistory() failed.")
  2236.                 history = []
  2237.             
  2238.             history.reverse()
  2239.  
  2240.             for h in history:
  2241.                 result.append(Event(*tuple(h)))
  2242.                 
  2243.             try:
  2244.                 self.error_code = result[0].event_code
  2245.             except IndexError:
  2246.                 self.error_code = STATUS_UNKNOWN
  2247.                 
  2248.             self.error_state = STATUS_TO_ERROR_STATE_MAP.get(self.error_code, ERROR_STATE_CLEAR)
  2249.             
  2250.         else:
  2251.             self.error_code = STATUS_UNKNOWN
  2252.             self.error_state = ERROR_STATE_CLEAR
  2253.  
  2254.         self.hist = result
  2255.         return result
  2256.  
  2257.  
  2258.  
  2259.     def getEWSUrl(self, url, stream):
  2260.         try:
  2261.             if self.is_local:
  2262.                 url2 = "%s&loc=%s" % (self.device_uri.replace('hpfax:', 'hp:'), url)
  2263.                 data = self
  2264.             else:
  2265.                 url2 = "http://%s%s" % (self.host, url)
  2266.                 data = None
  2267.  
  2268.             log.debug("Opening: %s" % url2)
  2269.             opener = LocalOpener({})
  2270.             try:
  2271.                 f = opener.open(url2, data)
  2272.             except Error:
  2273.                 log.error("Status read failed: %s" % url2)
  2274.                 stream.seek(0)
  2275.                 stream.truncate()
  2276.             else:
  2277.                 try:
  2278.                     stream.write(f.read())
  2279.                 finally:
  2280.                     f.close()
  2281.  
  2282.         finally:
  2283.             self.closeEWS()
  2284.  
  2285.  
  2286.     def downloadFirmware(self, usb_bus_id=None, usb_device_id=None):
  2287.         ok = False
  2288.         filename = os.path.join(prop.data_dir, "firmware", self.model.lower() + '.fw.gz')
  2289.         log.debug(filename)
  2290.  
  2291.         if os.path.exists(filename):
  2292.             log.debug("Downloading firmware file '%s'..." % filename)
  2293.  
  2294.             # Write to port directly (no MUD) so that HAL can enumerate the printer
  2295.             if 0: # this currently doesn't work because usblp is loaded...
  2296.             #if usb_bus_id is not None and usb_device_id is not None:
  2297.                 try:
  2298.                     p = "/dev/bus/usb/%s/%s" % (usb_bus_id, usb_device_id)
  2299.                     log.debug("Writing to %s..." % p)
  2300.                     #f = file(p, 'w')
  2301.                     f = os.open(p, os.O_RDWR)
  2302.                     x = gzip.open(filename).read()
  2303.                     os.write(f, x)
  2304.                     #f.close()
  2305.                     os.close(f)
  2306.                     ok = True
  2307.                     log.debug("OK")
  2308.                 except (OSError, IOError), e:
  2309.                     log.error("An error occured: %s" % e)
  2310.             else:
  2311.                 try:
  2312.                     self.openPrint()
  2313.                     bytes_written = self.writePrint(gzip.open(filename).read())
  2314.                     log.debug("%s bytes downloaded." % utils.commafy(bytes_written))
  2315.                     self.closePrint()
  2316.                     ok = True
  2317.                     log.debug("OK")
  2318.                 except Error, e:
  2319.                     log.error("An error occured: %s" % e.msg)
  2320.         else:
  2321.             log.error("Firmware file '%s' not found." % filename)
  2322.  
  2323.         return ok
  2324.  
  2325.  
  2326. # ********************************** Support classes/functions
  2327.  
  2328.  
  2329. class xStringIO(StringIO.StringIO):
  2330.     def makefile(self, x, y):
  2331.         return self
  2332.  
  2333. # URLs: hp:/usb/HP_LaserJet_3050?serial=00XXXXXXXXXX&loc=/hp/device/info_device_status.xml
  2334. class LocalOpener(urllib.URLopener):
  2335.     def open_hp(self, url, dev):
  2336.         log.debug("open_hp(%s)" % url)
  2337.  
  2338.         match_obj = http_pat_url.search(url)
  2339.         bus = match_obj.group(1) or ''
  2340.         model = match_obj.group(2) or ''
  2341.         serial = match_obj.group(3) or ''
  2342.         device = match_obj.group(4) or ''
  2343.         loc = match_obj.group(5) or ''
  2344.  
  2345.         dev.openEWS()
  2346.         dev.writeEWS("""GET %s HTTP/1.0\nContent-Length:0\nHost:localhost\nUser-Agent:hplip\n\n""" % loc)
  2347.  
  2348.         reply = xStringIO()
  2349.  
  2350.         while dev.readEWS(8192, reply, timeout=1):
  2351.             pass
  2352.  
  2353.         reply.seek(0)
  2354.         log.log_data(reply.getvalue())
  2355.  
  2356.         response = httplib.HTTPResponse(reply)
  2357.         response.begin()
  2358.  
  2359.         if response.status != httplib.OK:
  2360.             raise Error(ERROR_DEVICE_STATUS_NOT_AVAILABLE)
  2361.         else:
  2362.             return response.fp
  2363.  
  2364.  
  2365.